package org.spiderflow.mongodb.service.impl;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.result.DeleteResult;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import org.spiderflow.mongodb.executor.function.MongoFunctionExecutor;
import org.spiderflow.mongodb.model.FileDocument;
import org.spiderflow.mongodb.service.IFileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Field;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

/**
 * @author 双鱼冲
 * @ClassName:FileSercieImpl
 * @Description: (这里用一句话描述这个类的作用)
 * @date 2020-11-14
 * @since 1.0
 */
@Service("fileService")
public class FileServiceImpl implements IFileService {

  private static final String collectionName = "fileDatas";

  @Autowired
  private MongoFunctionExecutor mongoFunctionExecutor;

  /**
   * 表单上传附件
   */
  @Override
  public FileDocument saveFile(String alias, String md5, MultipartFile file) {
    //已存在该文件，则实现秒传
    FileDocument fileDocument = getByMd5(alias, md5);
    if (fileDocument != null) {
      return fileDocument;
    }

    fileDocument = new FileDocument();
    fileDocument.setName(file.getOriginalFilename());
    fileDocument.setSize(file.getSize());
    fileDocument.setContentType(file.getContentType());
    fileDocument.setUploadDate(new Date());
    fileDocument.setMd5(md5);
    String suffix = file.getOriginalFilename()
        .substring(file.getOriginalFilename().lastIndexOf("."));
    fileDocument.setSuffix(suffix);

    try {
      //文件存入gridfs
      String gridfsId = uploadFileToGridFS(alias, file.getInputStream(), file.getContentType());
      fileDocument.setGridfsId(gridfsId);
      //上传的信息保存在mongodb
      mongoFunctionExecutor.getMongoTemplate(alias).save(fileDocument, collectionName);
    } catch (IOException ex) {
      ex.printStackTrace();
    }
    return fileDocument;
  }

  /**
   * 上传文件到Mongodb的GridFs中
   */
  @Override
  public String uploadFileToGridFS(String alias, InputStream in, String contentType) {
    String gridfsId = IdUtil.simpleUUID();
    //文件，存储在GridFS中
    mongoFunctionExecutor.gridFsTemplate(alias).store(in, gridfsId, contentType);
    return gridfsId;
  }

  /**
   * 删除附件
   *
   * @param id 文件id
   * @param isDeleteFile 是否删除文件
   */
  @Override
  public void removeFile(String alias, String id, boolean isDeleteFile) {
    FileDocument fileDocument = mongoFunctionExecutor.getMongoTemplate(alias)
        .findById(id, FileDocument.class, collectionName);
    if (fileDocument != null) {
      Query query = new Query().addCriteria(Criteria.where("_id").is(id));
      DeleteResult result = mongoFunctionExecutor.getMongoTemplate(alias)
          .remove(query, collectionName);
      System.out.println("result:" + result.getDeletedCount());

      if (isDeleteFile) {
        Query deleteQuery = new Query()
            .addCriteria(Criteria.where("filename").is(fileDocument.getGridfsId()));
        mongoFunctionExecutor.gridFsTemplate(alias).delete(deleteQuery);
      }
    }
  }

  /**
   * 查询附件
   *
   * @param id 文件id
   */
  @Override
  public Optional<FileDocument> getFileById(String alias, String id) {
    FileDocument fileDocument = mongoFunctionExecutor.getMongoTemplate(alias)
        .findById(id, FileDocument.class, collectionName);
    if (fileDocument != null) {
      Query gridQuery = new Query()
          .addCriteria(Criteria.where("filename").is(fileDocument.getGridfsId()));
      try {
        GridFSFile fsFile = mongoFunctionExecutor.gridFsTemplate(alias).findOne(gridQuery);
        GridFSDownloadStream in = mongoFunctionExecutor.getGridFSBucket(alias)
            .openDownloadStream(fsFile.getObjectId());
        if (in.getGridFSFile().getLength() > 0) {
          GridFsResource resource = new GridFsResource(fsFile, in);
          fileDocument.setContent(IoUtil.readBytes(resource.getInputStream()));
          return Optional.of(fileDocument);
        } else {
          fileDocument = null;
          return Optional.empty();
        }
      } catch (IOException ex) {
        ex.printStackTrace();
      }
    }
    return Optional.empty();
  }

  /**
   * 根据md5获取文件对象
   */
  @Override
  public FileDocument getByMd5(String alias, String md5) {
    Query query = new Query().addCriteria(Criteria.where("md5").is(md5));
    FileDocument fileDocument = mongoFunctionExecutor.getMongoTemplate(alias)
        .findOne(query, FileDocument.class, collectionName);
    return fileDocument;
  }

  //文件上传列表
  @Override
  public List<FileDocument> listFilesByPage(String alias, int pageIndex, int pageSize) {
    Query query = new Query().with(new Sort(Sort.Direction.DESC, "uploadDate"));
    long skip = (pageIndex - 1) * pageSize;
    query.skip(skip);
    query.limit(pageSize);
    Field field = query.fields();
    field.exclude("content");
    List<FileDocument> files = mongoFunctionExecutor.getMongoTemplate(alias)
        .find(query, FileDocument.class, collectionName);
    return files;
  }


}
